package org.yypm;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.*;
import java.util.Date;

/**
 * @author 云烟飘渺o
 * @version 1.0
 * @description 借巨人之力，加速你的成长之路
 */
public class DefaultSqlSession implements SqlSession {

    private Connection connection;

    private Map<String, XNode> mapperElement;


    public DefaultSqlSession(Connection connection, Map<String, XNode> mapperElement) {
        this.connection = connection;
        this.mapperElement = mapperElement;
    }

    @Override
    public <T> T selectOne(String statement) {
        try {
            XNode xNode = mapperElement.get(statement);
            String sql = xNode.getSql();
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            ResultSet resultSet = preparedStatement.executeQuery();
            List<T> obs = resultSet2Object(resultSet, Class.forName(xNode.getResultType()));
            return obs.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public <T> T selectOne(String statement, Object param) {
        try {
            XNode xNode = mapperElement.get(statement);
            Map<Integer, String> parameter = xNode.getParameter();
            String sql = xNode.getSql();
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            buildParameter(preparedStatement, param, parameter);
            ResultSet resultSet = preparedStatement.executeQuery();
            List<T> obs = resultSet2Object(resultSet, Class.forName(xNode.getResultType()));
            return obs.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void buildParameter(PreparedStatement preparedStatement, Object param, Map<Integer, String> parameter) throws SQLException, IllegalAccessException {
        //单个参数
        int size = parameter.size();
        if (param instanceof Long) {
            for (int i = 1; i <= size; i++) {
                preparedStatement.setLong(i, Long.parseLong(param.toString()));
            }
            return;
        }
        if (param instanceof Integer) {
            for (int i = 1; i <= size; i++) {
                preparedStatement.setInt(i, Integer.parseInt(param.toString()));
            }
            return;
        }
        if (param instanceof String) {
            for (int i = 1; i <= size; i++) {
                preparedStatement.setString(i, param.toString());
            }
            return;
        }
        //对象参数
        Map<String, Object> fieldMap = new HashMap<>();
        Field[] declaredFields = param.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            String name = field.getName();
            field.setAccessible(true);
            Object v = field.get(param);
            field.setAccessible(false);
            fieldMap.put(name, v);
        }
        for (int i = 1; i <= size; i++) {
            String parameterDefine = parameter.get(i);
            Object o = fieldMap.get(parameterDefine);
            if (o instanceof Long) {
                preparedStatement.setLong(i, Long.parseLong(o.toString()));
                continue;
            }
            if (o instanceof Integer) {
                preparedStatement.setInt(i, Integer.parseInt(o.toString()));
                continue;
            }
            if (o instanceof Short) {
                preparedStatement.setShort(i, Short.parseShort(o.toString()));
                continue;
            }
            if (o instanceof String) {
                preparedStatement.setString(i, o.toString());
                continue;
            }
            if (o instanceof Date) {
                preparedStatement.setDate(i, (java.sql.Date) o);
            }
        }
    }


    /**
     * 1.将结果集转换为目标对象
     *
     * @param resultSet
     * @param aClass
     * @param <T>
     * @return
     */
    private static <T> List<T> resultSet2Object(ResultSet resultSet, Class<?> aClass) {
        List<T> list = new ArrayList<>();
        try {
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();

            while (resultSet.next()) {
                T t = (T) aClass.newInstance();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = metaData.getColumnName(i);//name
                    Object value = resultSet.getObject(columnName);
                    //setName
                    String setMethodName = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                    Method method;
                    if (value instanceof Timestamp) {
                        method = aClass.getMethod(setMethodName, Date.class);
                    } else {
                        method = aClass.getMethod(setMethodName, value.getClass());
                    }
                    method.invoke(t, value);
                }
                list.add(t);
            }
        } catch (
                Exception e) {
            e.printStackTrace();
        }
        return list;
    }


    @Override
    public <T> List<T> selectList(String statement) {
        return null;
    }

    @Override
    public <T> List<T> selectList(String statement, Object param) {
        return null;
    }

    @Override
    public void close() {

    }


}
